home *** CD-ROM | disk | FTP | other *** search
- /* This file contains a driver for the WD winchester controller from
- * Western Digital (WX-2 and related controllers).
- *
- * Original code written by Adri Koppes.
- * Patches from Gary Oliver for use with the Western Digital WX-2.
- * Patches from Harry McGavran for robust operation on turbo clones.
- * Patches from Mike Mitchell for WX-2 auto configure operation.
- *
- * The driver supports two operations: read a block and
- * write a block. It accepts two messages, one for reading and one for
- * writing, both using message format m2 and with the same parameters:
- *
- * m_type DEVICE PROC_NR COUNT POSITION ADRRESS
- * ----------------------------------------------------------------
- * | DISK_READ | device | proc nr | bytes | offset | buf ptr |
- * |------------+---------+---------+---------+---------+---------|
- * | DISK_WRITE | device | proc nr | bytes | offset | buf ptr |
- * ----------------------------------------------------------------
- *
- * The file contains one entry point:
- *
- * winchester_task: main entry when system is brought up
- *
- */
-
- #include "../h/const.h"
- #include "../h/type.h"
- #include "../h/callnr.h"
- #include "../h/com.h"
- #include "../h/error.h"
- #include "const.h"
- #include "type.h"
- #include "proc.h"
-
- #define AU TO_BIOS TRUE /* TRUE: use Western's autoconfig BIOS */
- #define DEBUG FALSE /* TRUE: enable debug messages */
- #define MONITOR TRUE /* TRUE: monitor performance of busy loops */
- #define MAX_DRIVES 1
-
- /* I/O Ports used by winchester disk task. */
- #define WIN_DATA 0x320 /* winchester disk controller data register */
- #define WIN_STATUS 0x321 /* winchester disk controller status register */
- #define WST_REQ 0x001 /* Request bit */
- #define WST_INPUT 0x002 /* Set if controller is writing to cpu */
- #define WST_BUS 0x004 /* Command/status bit */
- #define WST_BUSY 0x008 /* Busy */
- #define WST_INTERRUPT 0x020 /* Interrupt generated ?? */
- #define WIN_SELECT 0x322 /* winchester disk controller select port */
- #define WIN_DMA 0x323 /* winchester disk controller dma register */
- #define DMA_ADDR 0x006 /* port for low 16 bits of DMA address */
- #define DMA_TOP 0x082 /* port for top 4 bits of 20-bit DMA addr */
- #define DMA_COUNT 0x007 /* port for DMA count (count = bytes - 1) */
- #define DMA_M2 0x00C /* DMA status port */
- #define DMA_M1 0x00B /* DMA status port */
- #define DMA_INIT 0x00A /* DMA init port */
-
- /* Winchester disk controller command bytes. */
- #define WIN_RECALIBRATE 0x01 /* command for the drive to recalibrate */
- #define WIN_SENSE 0x03 /* command for the controller to get its status */
- #define WIN_READ 0x08 /* command for the drive to read */
- #define WIN_WRITE 0x0a /* command for the drive to write */
- #define WIN_SPECIFY 0x0C /* command for the controller to accept params */
- #define WIN_ECC_READ 0x0D /* command for the controller to read ecc length */
-
- #define DMA_INT 3 /* Command with dma and interrupt */
- #define INT 2 /* Command with interrupt, no dma */
- #define NO_DMA_INT 0 /* Command without dma and interrupt */
-
- /* DMA channel commands. */
- #define DMA_READ 0x47 /* DMA read opcode */
- #define DMA_WRITE 0x4B /* DMA write opcode */
-
- /* Parameters for the disk drive. */
- #define SECTOR_SIZE 512 /* physical sector size in bytes */
- #define NR_SECTORS 0x11 /* number of sectors per track */
-
- /* Error codes */
- #define ERR -1 /* general error */
-
- /* Miscellaneous. */
- #define MAX_ERRORS 4 /* how often to try rd/wt before quitting */
- #define MAX_RESULTS 4 /* max number of bytes controller returns */
- #define NR_DEVICES 10 /* maximum number of drives */
- #define MAX_WIN_RETRY 32000 /* max # times to try to output to WIN */
- #define PART_TABLE 0x1C6 /* IBM partition table starts here in sect 0 */
- #define DEV_PER_DRIVE 5 /* hd0 + hd1 + hd2 + hd3 + hd4 = 5 */
- #if AUTO_BIOS
- #define AUTO_PARAM 0x1AD /* drive parameter table starts here in sect 0 */
- #define AUTO_ENABLE 0x10 /* auto bios enabled bit from status reg */
- /* some start up parameters in order to extract the drive parameter table */
- /* from the winchester. these should not need changed. */
- #define AUTO_CYLS 306 /* default number of cylinders */
- #define AUTO_HEADS 4 /* default number of heads */
- #define AUTO_RWC 307 /* default reduced write cylinder */
- #define AUTO_WPC 307 /* default write precomp cylinder */
- #define AUTO_ECC 11 /* default ecc burst */
- #define AUTO_CTRL 5 /* default winchester stepping speed byte */
- #endif
-
- /* Variables. */
- PRIVATE struct wini { /* main drive struct, one entry per drive */
- int wn_opcode; /* DISK_READ or DISK_WRITE */
- int wn_procnr; /* which proc wanted this operation? */
- int wn_drive; /* drive number addressed (<< 5) */
- int wn_cylinder; /* cylinder number addressed */
- int wn_sector; /* sector addressed */
- int wn_head; /* head number addressed */
- int wn_heads; /* maximum number of heads */
- int wn_ctrl_byte; /* Control byte for COMMANDS (10-Apr-87 GO) */
- long wn_low; /* lowest cylinder of partition */
- long wn_size; /* size of partition in blocks */
- int wn_count; /* byte count */
- vir_bytes wn_address; /* user virtual address */
- char wn_results[MAX_RESULTS]; /* the controller can give lots of output */
- } wini[NR_DEVICES];
-
- PRIVATE int w_need_reset = FALSE; /* set to 1 when controller must be reset */
- PRIVATE int nr_drives; /* Number of drives */
-
- PRIVATE message w_mess; /* message buffer for in and out */
-
- PRIVATE int command[6]; /* Common command block */
-
- PRIVATE unsigned char buf[BLOCK_SIZE]; /* Buffer used by the startup routine */
-
- PRIVATE struct param {
- int nr_cyl; /* Number of cylinders */
- int nr_heads; /* Number of heads */
- int reduced_wr; /* First cylinder with reduced write current */
- int wr_precomp; /* First cylinder with write precompensation */
- int max_ecc; /* Maximum ECC burst length */
- int ctrl_byte; /* Copied control-byte from bios tables */
- } param0, param1;
-
-
- /*=========================================================================*
- * winchester_task *
- *=========================================================================*/
- PUBLIC winchester_task()
- {
- /* Main program of the winchester disk driver task. */
-
- int r, caller, proc_nr;
-
- /* First initialize the controller */
- init_params();
-
- /* Here is the main loop of the disk task. It waits for a message, carries
- * it out, and sends a reply.
- */
-
- while (TRUE) {
- /* First wait for a request to read or write a disk block. */
- receive(ANY, &w_mess); /* get a request to do some work */
- if (w_mess.m_source < 0) {
- printf("winchester task got message from %d ", w_mess.m_source);
- continue;
- }
- caller = w_mess.m_source;
- proc_nr = w_mess.PROC_NR;
-
- /* Now carry out the work. */
- switch(w_mess.m_type) {
- case DISK_READ:
- case DISK_WRITE: r = w_do_rdwt(&w_mess); break;
- default: r = EINVAL; break;
- }
-
- /* Finally, prepare and send the reply message. */
- w_mess.m_type = TASK_REPLY;
- w_mess.REP_PROC_NR = proc_nr;
-
- w_mess.REP_STATUS = r; /* # of bytes transferred or error code */
- send(caller, &w_mess); /* send reply to caller */
- }
- }
-
-
- /*==========================================================================*
- * w_do_rdwt *
- *==========================================================================*/
- PRIVATE int w_do_rdwt(m_ptr)
- message *m_ptr; /* pointer to read or write w_message */
- {
- /* Carry out a read or write request from the disk. */
- register struct wini *wn;
- int r, device, errors = 0;
- long sector;
-
- /* Decode the w_message parameters. */
- device = m_ptr->DEVICE;
- if (device < 0 || device >= NR_DEVICES)
- return(EIO);
- if (m_ptr->COUNT != BLOCK_SIZE)
- return(EINVAL);
- wn = &wini[device]; /* 'wn' points to entry for this drive */
-
- wn->wn_opcode = m_ptr->m_type; /* DISK_READ or DISK_WRITE */
- if (m_ptr->POSITION % BLOCK_SIZE != 0)
- return(EINVAL);
- sector = m_ptr->POSITION/SECTOR_SIZE;
- if ((sector+BLOCK_SIZE/SECTOR_SIZE) > wn->wn_size)
- return(EOF);
- sector += wn->wn_low;
- wn->wn_cylinder = sector / (wn->wn_heads * NR_SECTORS);
- wn->wn_sector = (sector % NR_SECTORS);
- wn->wn_head = (sector % (wn->wn_heads * NR_SECTORS) )/NR_SECTORS;
- wn->wn_count = m_ptr->COUNT;
- wn->wn_address = (vir_bytes) m_ptr->ADDRESS;
- wn->wn_procnr = m_ptr->PROC_NR;
-
- /* This loop allows a failed operation to be repeated. */
- while (errors <= MAX_ERRORS) {
- errors++; /* increment count once per loop cycle */
- if (errors >= MAX_ERRORS)
- return(EIO);
-
- /* First check to see if a reset is needed. */
- if (w_need_reset) w_reset();
-
- /* Now set up the DMA chip. */
- w_dma_setup(wn);
-
- /* Perform the transfer. */
- r = w_transfer(wn);
- if (r == OK) break; /* if successful, exit loop */
-
- }
-
- return(r == OK ? BLOCK_SIZE : EIO);
- }
-
-
- /*==========================================================================*
- * w_dma_setup *
- *==========================================================================*/
- PRIVATE w_dma_setup(wn)
- struct wini *wn; /* pointer to the drive struct */
- {
- /* The IBM PC can perform DMA operations by using the DMA chip. To use it,
- * the DMA (Direct Memory Access) chip is loaded with the 20-bit memory address
- * to by read from or written to, the byte count minus 1, and a read or write
- * opcode. This routine sets up the DMA chip. Note that the chip is not
- * capable of doing a DMA across a 64K boundary (e.g., you can't read a
- * 512-byte block starting at physical address 65520).
- */
-
- int mode, low_addr, high_addr, top_addr, low_ct, high_ct, top_end;
- vir_bytes vir, ct;
- phys_bytes user_phys;
- extern phys_bytes umap();
-
- mode = (wn->wn_opcode == DISK_READ ? DMA_READ : DMA_WRITE);
- vir = (vir_bytes) wn->wn_address;
- ct = (vir_bytes) wn->wn_count;
- user_phys = umap(proc_addr(wn->wn_procnr), D, vir, ct);
- low_addr = (int) user_phys & BYTE;
- high_addr = (int) (user_phys >> 8) & BYTE;
- top_addr = (int) (user_phys >> 16) & BYTE;
- low_ct = (int) (ct - 1) & BYTE;
- high_ct = (int) ( (ct - 1) >> 8) & BYTE;
-
- /* Check to see if the transfer will require the DMA address counter to
- * go from one 64K segment to another. If so, do not even start it, since
- * the hardware does not carry from bit 15 to bit 16 of the DMA address.
- * Also check for bad buffer address. These errors mean FS contains a bug.
- */
- if (user_phys == 0)
- panic("FS gave winchester disk driver bad addr", (int) vir);
- top_end = (int) (((user_phys + ct - 1) >> 16) & BYTE);
- if (top_end != top_addr) panic("Trying to DMA across 64K boundary", top_addr);
-
- /* Now set up the DMA registers. */
- lock();
- port_out(DMA_M2, mode); /* set the DMA mode */
- port_out(DMA_M1, mode); /* set it again */
- port_out(DMA_ADDR, low_addr); /* output low-order 8 bits */
- port_out(DMA_ADDR, high_addr);/* output next 8 bits */
- port_out(DMA_TOP, top_addr); /* output highest 4 bits */
- port_out(DMA_COUNT, low_ct); /* output low 8 bits of count - 1 */
- port_out(DMA_COUNT, high_ct); /* output high 8 bits of count - 1 */
- unlock();
- }
-
- /*=========================================================================*
- * w_transfer *
- *=========================================================================*/
- PRIVATE int w_transfer(wn)
- register struct wini *wn; /* pointer to the drive struct */
- {
- /* The drive is now on the proper cylinder. Read or write 1 block. */
-
- /* The command is issued by outputing 6 bytes to the controller chip. */
- command[0] = (wn->wn_opcode == DISK_READ ? WIN_READ : WIN_WRITE);
- command[1] = wn->wn_head | wn->wn_drive;
- command[2] = (((wn->wn_cylinder & 0x0300) >> 2) | wn->wn_sector);
- command[3] = (wn->wn_cylinder & 0xFF);
- command[4] = BLOCK_SIZE/SECTOR_SIZE;
- command[5] = wn->wn_ctrl_byte;
-
- if (com_out(DMA_INT) != OK)
- return(ERR);
-
- port_out(DMA_INIT, 3); /* initialize DMA */
- /* Block, waiting for disk interrupt. */
- w_wait_int();
-
- /* Get controller status and check for errors. */
- if (win_results(wn) == OK)
- return(OK);
- if ((wn->wn_results[0] & 63) == 24)
- read_ecc();
- else
- w_need_reset = TRUE;
- return(ERR);
- }
-
-
- /*===========================================================================*
- * win_results *
- *===========================================================================*/
- PRIVATE int win_results(wn)
- register struct wini *wn; /* pointer to the drive struct */
- {
- /* Extract results from the controller after an operation. */
-
- register int i;
- int status;
-
- port_in(WIN_DATA, &status);
- port_out(WIN_DMA, 0);
- if (!(status & 2)) /* Test "error" bit */
- return(OK);
- command[0] = WIN_SENSE;
- command[1] = wn->wn_drive;
- if (com_out(NO_DMA_INT) != OK)
- return(ERR);
-
- /* Loop, extracting bytes from WIN */
- for (i = 0; i < MAX_RESULTS; i++) {
- if (hd_wait(WST_REQ) != OK)
- return(ERR);
- port_in(WIN_DATA, &status);
- wn->wn_results[i] = status & BYTE;
- }
- if(hd_wait(WST_REQ) != OK) /* Missing from */
- return (ERR); /* Original. 11-Apr-87 G.O. */
-
- port_in(WIN_DATA, &status); /* Read "error" flag */
-
- if(((status & 2) != 0) || (wn->wn_results[0] & 0x3F)) {
- return(ERR);
- } else
- return(OK);
- }
-
-
- /*===========================================================================*
- * win_out *
- *===========================================================================*/
- PRIVATE win_out(val)
- int val; /* write this byte to winchester disk controller */
- {
- /* Output a byte to the controller. This is not entirely trivial, since you
- * can only write to it when it is listening, and it decides when to listen.
- * If the controller refuses to listen, the WIN chip is given a hard reset.
- */
- int r;
-
- if (w_need_reset) return; /* if controller is not listening, return */
-
- do {
- port_in(WIN_STATUS, &r);
- } while((r & (WST_REQ | WST_BUSY)) == WST_BUSY);
-
- port_out(WIN_DATA, val);
- }
-
- /*===========================================================================*
- * w_reset *
- *===========================================================================*/
- PRIVATE w_reset()
- {
- /* Issue a reset to the controller. This is done after any catastrophe,
- * like the controller refusing to respond.
- */
-
- int r = 0, i;
-
- /* Strobe reset bit low. */
- port_out(WIN_STATUS, 0);
-
- for(i = MAX_WIN_RETRY/10; i; --i)
- ; /* Spin loop for a while */
-
- port_out(WIN_SELECT, 0); /* Issue select pulse */
- for (i = 0; i < MAX_WIN_RETRY; i++) {
- port_in(WIN_STATUS, &r);
- if(r & 0x30) /* What is 10? 20 = INTERRUPT */
- return (ERR);
-
- if((r & (WST_BUSY | WST_BUS | WST_REQ)) ==
- (WST_BUSY | WST_BUS | WST_REQ))
- break;
- }
-
- if (i == MAX_WIN_RETRY) {
- printf("Hard disk won't reset, status = %x\n", r);
- return(ERR);
- }
-
- /* Reset succeeded. Tell WIN drive parameters. */
- w_need_reset = FALSE;
-
- if(win_specify(0, ¶m0) != OK)
- return (ERR);
-
-
- if ((nr_drives > 1) && (win_specify(1, ¶m1) != OK))
- return(ERR);
-
-
- for (i=0; i<nr_drives; i++) {
- command[0] = WIN_RECALIBRATE;
- command[1] = i << 5;
- command[5] = wini[i * DEV_PER_DRIVE].wn_ctrl_byte;
-
-
- if (com_out(INT) != OK)
- return(ERR);
-
- w_wait_int();
-
- if (win_results(&wini[i * DEV_PER_DRIVE]) != OK) {
- w_need_reset = TRUE;
- return(ERR);
- }
- }
- return(OK);
- }
-
-
- /*===========================================================================*
- * w_wait_int *
- *===========================================================================*/
- PRIVATE w_wait_int()
- {
- /*DEBUG: loop looking for 0x20 in status (I don't know what that is!!) */
- /* 10-Apr-87. G. Oliver */
- int r, i; /* Some local storage */
-
- receive(HARDWARE, &w_mess);
-
- port_out(DMA_INIT, 0x07); /* Disable int from DMA */
-
- for(i=0; i<MAX_WIN_RETRY; ++i) {
- port_in(WIN_STATUS, &r);
- if(r & WST_INTERRUPT)
- break; /* Exit if end of int */
- }
-
- #if MONITOR
- if(i > 10) { /* Some arbitrary limit below which we don't really care */
- if(i == MAX_WIN_RETRY)
- printf("wini: timeout waiting for INTERRUPT status\n");
- else
- printf("wini: %d loops waiting for INTERRUPT status\n", i);
- }
- #endif /* MONITOR */
- }
-
-
- /*============================================================================*
- * win_specify *
- *============================================================================*/
- PRIVATE win_specify(drive, paramp)
- int drive;
- struct param *paramp;
- {
- command[0] = WIN_SPECIFY; /* Specify some parameters */
- command[1] = drive << 5; /* Drive number */
-
- if (com_out(NO_DMA_INT) != OK) /* Output command block */
- return(ERR);
- lock();
-
- /* No. of cylinders (high byte) */
- win_out(paramp->nr_cyl >> 8);
-
- /* No. of cylinders (low byte) */
- win_out(paramp->nr_cyl);
-
- /* No. of heads */
- win_out(paramp->nr_heads);
-
- /* Start reduced write (high byte) */
- win_out(paramp->reduced_wr >> 8);
-
- /* Start reduced write (low byte) */
- win_out(paramp->reduced_wr);
-
- /* Start write precompensation (high byte) */
- win_out(paramp->wr_precomp >> 8);
-
- /* Start write precompensation (low byte) */
- win_out(paramp->wr_precomp);
-
- /* Ecc burst length */
- win_out(paramp->max_ecc);
- unlock();
-
- if (check_init() != OK) { /* See if controller accepted parameters */
- w_need_reset = TRUE;
- return(ERR);
- }
- else
- return(OK);
- }
-
- /*============================================================================*
- * check_init *
- *============================================================================*/
- PRIVATE check_init()
- {
- /* Routine to check if controller accepted the parameters */
- int r, s;
-
- if (hd_wait(WST_REQ | WST_INPUT) == OK) {
- port_in(WIN_DATA, &r);
-
- do {
- port_in(WIN_STATUS, &s);
- } while(s & WST_BUSY); /* Loop while still busy */
-
- if (r & 2) /* Test error bit */
- {
- return(ERR);
- }
- else
- return(OK);
- } else
- {
- return (ERR); /* Missing from original: 11-Apr-87 G.O. */
- }
- }
-
- /*============================================================================*
- * read_ecc *
- *============================================================================*/
- PRIVATE read_ecc()
- {
- /* Read the ecc burst-length and let the controller correct the data */
-
- int r;
-
- command[0] = WIN_ECC_READ;
- if (com_out(NO_DMA_INT) == OK && hd_wait(WST_REQ) == OK) {
- port_in(WIN_DATA, &r);
- if (hd_wait(WST_REQ) == OK) {
- port_in(WIN_DATA, &r);
- if (r & 1)
- w_need_reset = TRUE;
- }
- }
- return(ERR);
- }
-
- /*============================================================================*
- * hd_wait *
- *============================================================================*/
- PRIVATE hd_wait(bits)
- register int bits;
- {
- /* Wait until the controller is ready to receive a command or send status */
-
- register int i = 0;
- int r;
-
- do {
- port_in(WIN_STATUS, &r);
- r &= bits;
- } while ((i++ < MAX_WIN_RETRY) && r != bits); /* Wait for ALL bits */
-
- if (i >= MAX_WIN_RETRY) {
- w_need_reset = TRUE;
- return(ERR);
- } else
- return(OK);
- }
-
- /*============================================================================*
- * com_out *
- *============================================================================*/
- PRIVATE com_out(mode)
- int mode;
- {
- /* Output the command block to the winchester controller and return status */
-
- register int i;
- int r;
-
- port_out(WIN_DMA, mode);
- port_out(WIN_SELECT, mode);
- for (i=0; i<MAX_WIN_RETRY; i++) {
- port_in(WIN_STATUS, &r);
- if (r & WST_BUSY)
- break;
- }
-
- if (i == MAX_WIN_RETRY) {
- w_need_reset = TRUE;
- return(ERR);
- }
-
-
- lock();
-
- for (i=0; i<6; i++) {
- if(hd_wait(WST_REQ) != OK)
- break; /* No data request pending */
-
- port_in(WIN_STATUS, &r);
-
- if((r & (WST_BUSY | WST_BUS | WST_INPUT)) !=
- (WST_BUSY | WST_BUS))
- break;
-
- port_out(WIN_DATA, command[i]);
- }
-
- unlock();
-
- if(i != 6) {
- return(ERR);
- }
- else
- return(OK);
- }
-
- /*============================================================================*
- * init_params *
- *============================================================================*/
- PRIVATE init_params()
- {
- /* This routine is called at startup to initialize the partition table,
- * the number of drives and the controller
- */
- unsigned int i, segment, offset;
- int type_0, type_1;
- phys_bytes address;
- extern phys_bytes umap();
- extern int vec_table[];
-
- /* Get the number of drives from the bios */
- phys_copy(0x475L, umap(proc_addr(WINCHESTER), D, buf, 1), 1L);
- nr_drives = (int) *buf > MAX_DRIVES ? MAX_DRIVES : (int) *buf;
-
- /* Read the switches from the controller */
- port_in(WIN_SELECT, &i);
-
- #if AUTO_BIOS
- /* Get the drive parameters from sector zero of the drive if the */
- /* autoconfig mode of the controller has been selected */
-
- if(i & AUTO_ENABLE) {
-
- /* set up some phoney parameters so that we can read the first sector */
- /* from the winchester. all drives will have one cylinder and one head */
- /* but set up initially to the mini scribe drives from ibm */
- param1.nr_cyl = param0.nr_cyl = AUTO_CYLS;
- param1.nr_heads = param0.nr_heads = AUTO_HEADS;
- param1.reduced_wr = param0.reduced_wr = AUTO_RWC;
- param1.wr_precomp = param0.wr_precomp = AUTO_WPC;
- param1.max_ecc = param0.max_ecc = AUTO_ECC;
- param1.ctrl_byte = param0.ctrl_byte = AUTO_CTRL;
- wini[DEV_PER_DRIVE].wn_heads = wini[0].wn_heads = param0.nr_heads;
- wini[DEV_PER_DRIVE].wn_low = wini[0].wn_low = 0L;
- wini[DEV_PER_DRIVE].wn_size = wini[0].wn_size = (long)AUTO_CYLS * (long)AUTO_HEADS * (long)NR_SECTORS;
- if(w_reset() != OK)
- panic("cannot setup for reading winchester parameter tables",0);
-
- if (nr_drives > 1) {
-
- /* generate the request to read the first sector from the winchester */
- w_mess.DEVICE = DEV_PER_DRIVE;
- w_mess.POSITION = 0L;
- w_mess.COUNT = BLOCK_SIZE;
- w_mess.ADDRESS = (char *) buf;
- w_mess.PROC_NR = WINCHESTER;
- w_mess.m_type = DISK_READ;
- if(w_do_rdwt(&w_mess) != BLOCK_SIZE)
- panic("cannot read drive parameters from winchester",DEV_PER_DRIVE);
-
- /* copy the parameter tables into the structures for later use */
- copy_param(&buf[AUTO_PARAM], ¶m1);
-
- }
-
- /* generate the request to read the first sector from the winchester */
- w_mess.DEVICE = 0;
- w_mess.POSITION = 0L;
- w_mess.COUNT = BLOCK_SIZE;
- w_mess.ADDRESS = (char *) buf;
- w_mess.PROC_NR = WINCHESTER;
- w_mess.m_type = DISK_READ;
- if(w_do_rdwt(&w_mess) != BLOCK_SIZE)
- panic("cannot read drive parameters from winchester", 0);
-
- /* copy the parameter tables into the structures for later use */
- copy_param(&buf[AUTO_PARAM], ¶m0);
-
-
- /* whoever compiled the kernel wanted the auto bios code included. if it
- * turns out that the tables should be read from the rom, then handle
- * this case the regular way */
- } else {
- #endif
-
- /* Calculate the drive types */
- type_0 = i & 3;
- type_1 = (i >> 2) & 3;
-
- /* Copy the parameter vector from the saved vector table */
- offset = vec_table[2 * 0x41];
- segment = vec_table[2 * 0x41 + 1];
-
- /* Calculate the address off the parameters and copy them to buf */
- address = ((phys_bytes)segment << 4) + offset;
- phys_copy(address, umap(proc_addr(WINCHESTER), D, buf, 64), 64L);
-
- /* Copy the parameters to the structures */
- copy_param(&buf[type_0 * 16], ¶m0);
- copy_param(&buf[type_1 * 16], ¶m1);
-
- #if AUTO_BIOS
- /* close up the code to be executed when the controller has not been
- * set up to for auto configuration */
- }
- #endif
-
- /* Set the parameters in the drive structure */
- for (i = 0; i < DEV_PER_DRIVE; i++) {
- wini[i].wn_heads = param0.nr_heads;
- wini[i].wn_ctrl_byte = param0.ctrl_byte;
- wini[i].wn_drive = 0 << 5; /* Set drive number */
- }
-
- wini[0].wn_low = wini[DEV_PER_DRIVE].wn_low = 0L;
- wini[0].wn_size = (long)((long)param0.nr_cyl * (long)param0.nr_heads * (long)NR_SECTORS);
-
- for (i = DEV_PER_DRIVE; i < (2*DEV_PER_DRIVE); i++) {
- wini[i].wn_heads = param1.nr_heads;
- wini[i].wn_ctrl_byte = param1.ctrl_byte;
- wini[i].wn_drive = 1 << 5; /* Set drive number */
- }
- wini[DEV_PER_DRIVE].wn_size =
- (long)((long)param1.nr_cyl * (long)param1.nr_heads * (long)NR_SECTORS);
-
- /* Initialize the controller */
- if ((nr_drives > 0) && (w_reset() != OK))
- nr_drives = 0;
-
- /* Read the partition table for each drive and save them */
- for (i = 0; i < nr_drives; i++) {
- w_mess.DEVICE = i * DEV_PER_DRIVE;
- w_mess.POSITION = 0L;
- w_mess.COUNT = BLOCK_SIZE;
- w_mess.ADDRESS = (char *) buf;
- w_mess.PROC_NR = WINCHESTER;
- w_mess.m_type = DISK_READ;
- if (w_do_rdwt(&w_mess) != BLOCK_SIZE)
- panic("Can't read partition table of winchester ", i);
- copy_prt(i * DEV_PER_DRIVE);
- }
- }
-
- /*==========================================================================*
- * copy_params *
- *==========================================================================*/
- PRIVATE copy_params(src, dest)
- register unsigned char *src;
- register struct param *dest;
- {
- /* This routine copies the parameters from src to dest
- * and sets the parameters for partition 0 and DEV_PER_DRIVE
- */
-
- dest->nr_cyl = *(int *)src;
- dest->nr_heads = (int)src[2];
- dest->reduced_wr = *(int *)&src[3];
- dest->wr_precomp = *(int *)&src[5];
- dest->max_ecc = (int)src[7];
- dest->ctrl_byte = (int)src[8];
- }
-
- /*==========================================================================*
- * copy_prt *
- *==========================================================================*/
- PRIVATE copy_prt(drive)
- int drive;
- {
- /* This routine copies the partition table for the selected drive to
- * the variables wn_low and wn_size
- */
-
- register int i, offset;
- struct wini *wn;
- long adjust;
-
- for (i=0; i<4; i++) {
- adjust = 0;
- wn = &wini[i + drive + 1];
- offset = PART_TABLE + i * 0x10;
- wn->wn_low = *(long *)&buf[offset];
- if ((wn->wn_low % (BLOCK_SIZE/SECTOR_SIZE)) != 0) {
- adjust = wn->wn_low;
- wn->wn_low = (wn->wn_low/(BLOCK_SIZE/SECTOR_SIZE)+1)*(BLOCK_SIZE/SECTOR_SIZE);
- adjust = wn->wn_low - adjust;
- }
- wn->wn_size = *(long *)&buf[offset + sizeof(long)] - adjust;
- }
- sort(&wini[drive + 1]);
- }
-
- sort(wn)
- register struct wini *wn;
- {
- register int i,j;
-
- for (i=0; i<4; i++)
- for (j=0; j<3; j++)
- if ((wn[j].wn_low == 0) && (wn[j+1].wn_low != 0))
- swap(&wn[j], &wn[j+1]);
- else if (wn[j].wn_low > wn[j+1].wn_low && wn[j+1].wn_low != 0)
- swap(&wn[j], &wn[j+1]);
- }
-
- swap(first, second)
- register struct wini *first, *second;
- {
- register struct wini tmp;
-
- tmp = *first;
- *first = *second;
- *second = tmp;
- }
-
-